package top.jojoace.demo.api.v1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import top.jojoace.demo.Dao.User2;
import top.jojoace.demo.Dao.User3;
import top.jojoace.demo.Dao.UserInterface;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * @author 陈Ser
 * @ClassName HelloController
 * @description: TODO
 * @Date 2021/10/27 15:15
 * @Version 1.0
 */

//@Component    //普通注解，注入IOC容器
//@Service  //业务层
@Controller //控制层
//@Repository   //存储层

//@ResponseBody //使用该注解直接将 return 的数据作为 Response，在方法或类上注解
//@RestController   //效果同上之和，@Controller 加上 @ResponseBody。
@RequestMapping("")//定义前缀路由

@Lazy   //延迟实例化
public class HelloController {


    /**
     *     <h1>@Autowired注解</h1>
     *     <br>
     *
     *     <h2>@Autowired三种 类注入方式</h2>
     *     <p>注入顺序:</p>
     *     <p>构造器注入 -> IOC 反射注入 -> seter注入。重复注入时，以最后注入为主</p><br><br>
     *
     *     <h2>三种 类查找方式</h2>
     *     <h3>一、@Qualifier("user3")</h3>
     *     <p>    主动注入</p><br><br>
     *
     *     <h2>二、@Autowired(required=true)</h2>
     *     <p>    当required为false时，spring找不到该类时不报错，并注入null。</p><br><br>
     *
     *     <h3>三、byType -> @Primary -> byName 被动注入</h3>
     *     <p>    byType 根据实现类型进行匹配</p>
     *     <p>    若byType找到的 为接口，则寻找其唯一实现类</p>
     *     <p>    若实现类不唯一，则寻找具有 {@code @Primary} 注解的唯一实现类</p>
     *     <p>    若同一接口实现类具有 {@code @Primary} 注解的类不唯一，则报错。</p>
     *     <p>    若没有具有 {@code @Primary} 注解的实现类，则 byName 通过变量名进行匹配</p>
     *     <p>    若 byName 无法匹配 -> 报错</p><br><br><br><br>
     *
     *
     *     <h1>@Primary</h1>
     *     <p>对于byType的类型注入中
     *     <p>@Primary可提高所注解的类的优先级，使其优先注入</p>
     *     <p>byType中，对同一接口的实现类中，@Primary仅可注解其中某一个实现类。即，实现类中注解@Primary的类唯一,否则报错。</p>
     *
     *
     */
    //一、变量注入
    @Autowired  // byName与byType两种查找方式
    @Qualifier("user1")//主动注入
    private UserInterface user;

    @Autowired//使用优先级注入@Primary
    private UserInterface user_guess;

    @Autowired
    @Qualifier("haveValueUser")//主动注入 //使用byName注入，来自UserConfiguration
    private UserInterface valuesUser;


//    二、seter注入
    @Autowired
    public void setUser(User2 user) {
        this.user = user;
    }

    //三、构造注入
    @Autowired //可加可不加
    //在 Spring4.x 中增加了新的特性：如果类只提供了一个带参数的构造方法，则不需要对对其内部的属性写 @Autowired 注解，Spring 会自动为你注入属性。
    public HelloController(UserInterface user, UserInterface user_guess, UserInterface valuesUser) {
        this.user = user;
        this.user_guess = user_guess;
        this.valuesUser = valuesUser;
    }





    /**
     *     <h1>@Resource注解</h1>
     *     <br>
     *
     *     <h2>三种查找方式</h2>
     *     <p>默认按照ByName进行注入，由J2EE提供</p>
     *     <tage>如果name属性一旦指定，就只会按照名称进行装配。否则会报错</tage>
     *
     *     <h3> 一、默认安照名称进行装配，名称可以通过name属性进行指定 </h3>
     *     <code>
     *         @Resource(name="student") //没找到，或不唯一，则报错
     *         private Student student;
     *     </code>
     *
     *     <h3> 二、没有指定name属性,默认字段名称进行装配 </h3>
     *     <p> byName -> byType</p>
     *     <code>
     *         //未指定name，默认取将要注入属性的字段名，如下Student是类类型，student是属性名也就是字段名
     *         //当找不到与名称匹配的bean时才按照类型进行装配。
     *         @Resource()
     *         private Student student;
     *     </code>
     *
     *     <h3>三、写在setter方法上默认取setter对应的属性名进行装配。</h3>
     *     <code>
     *         @Resource(name="student")
     *         public void setStudent(Student student) {
     *             this.student = student;
     *         }
     *     </code>
     */
    //若同时指定name和type，则唯一指定，否则报错。
    @Resource(name = "user1",type = UserInterface.class)
    private UserInterface user1;




    //    @GetMapping("/hello")
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    // 效果同上，method定义请求类型
    public void sayHello(HttpServletResponse response) throws IOException {
        response.getWriter().write("Hello");

//      return "Hello";
//      没有Hello的JSP文件
        return;
    }

    @PostMapping("/hello")//POST请求
    @ResponseBody//使用该注解直接将 return 的数据作为 Response，在方法或类上注解
    public Object sayHelloResponse(HttpServletResponse response) throws IOException {

//        return "hello";
//        直接返回字符串

        this.user.sayClass();

        return new User3("name",1);
        //解析对象为JSON并返回
    }


    @ResponseBody
    @RequestMapping(path = "/hello",method = RequestMethod.OPTIONS)
    public Object sayConfigurationUser(){
        System.out.println("haveValue: "+this.valuesUser);
        return this.valuesUser;
    }

}
